<?php
require_once("main.php");

/**
 * @todo 1.Hacer que todas las propiedades menos db_link sean parte de una configuracion
 * 2.Hacer la clase estatica
 * 3.Que todas las operaciones devuelvan/reciban db_link para operar sobre el
 */
class ddbb extends main
{

    private $password = 'Megatron';
    private $user = 'root';
    private $server = 'localhost';
    private $db_link=NULL;
    private $database_name='economy';

    /**
     *
     * @param string $database_name Nombre de la base de datos
     * @param bool $debug Booleano, indica si estamos en entorno debug
     */
    function __construct($database_name = NULL, $debug = FALSE) {
        if($database_name)
            $this->database_name = $database_name;
        $this->debug = $debug;
    }

   /* Public Functions */

    /**
    * Esta funcion crea una conexion con la base de datos, y selecciona la base de datos.
    * Todo ello segun se corresponde con los valores que hay en las variables de la clase
    * "password, user, server y database_name" y guarda la conexion abierta en la variable "db_link"
    */
    public function connect($make_persistent = true) {
        if($this->debug)  $this->outline(func_get_args(), get_class($this) , "connect");
        // Conectamos con la base de datos
        $this->db_link = ($make_persistent)?
                mysql_pconnect($this->server,$this->user,$this->password):
                mysql_connect($this->server,$this->user,$this->password);

        if (!$this->db_link)
         die('Could not connect: ' . mysql_error());
        if($this->debug)
         echo 'Connected successfully with resource: ' . $this->db_link;
        if(!$this->select_database())
         die ('Database not specified');
    }

     /**
      * Cierra la conexion abierta en la variable "db_link"
      */
    public function close()
    {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "close");
      if(!mysql_close($this->db_link))
         die('Could not disconnect: ' . mysql_error());
      if($this->debug)
         echo 'Disconnected successfully';
    }
   
   public function set_database($name)
   /*Asigna el valor de la variable que especifica la base de datos con la que se va a conectar
   esta operacion deberia ser llamada antes que a la funcion "connect"*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "set_database");
      $this->database_name=$name;
   }
   
   /**
    * Selecciona mediante la conexion abierta los valores especificados por orden
    * en las columnas especificadas en la tabla dada
    *
    * @param string $table  tabla/s de la cual se hace la seleccion
    * @param array $fields  campos que selecciona de la/s tabla/s, por defecto todos
    * @param string $condicion condicion a cumplir los campos para ser selccionados, por defecto ninguna
    * @param array $limit   limites de seleccion, cuantos campos queremos que nos devuelva la consulta, por defecto todas
    * @return resource or false  resultado de la seleccion.
    *
    * @todo Si en la condicion hay alguna comilla fuera de lugar dará error y no se puede arreglar con:
    *   //Filtra las comillas simples
    *   $condition = $this->sql_filter($condition);
    */
    public function select($table, $fields = array("*"), $condition = FALSE, $limit = FALSE, $order = FALSE)
    {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "select");
      //Construye la consulta
      $sql = $this->build_sql_select($table, $fields, $condition, $limit, $order);
      //Realiza la consulta
      $result = $this->myquery($sql);
      if (!$result) {
         die('Invalid query: ' . mysql_error() . 'Function select');
      }
      return $result;
    }

   /**
    * Inserta mediante la conexion abierta los valores especificados por orden
    * en las columnas especificadas en la tabla dada.
    * 
    * @param string $table  nombre de la tabla en la que se va a realizar la insercion
    * @param array $columns nombre de las columnas en las que se van a insertar valores
    * @param array $values  valores insertados en cada columna. Se insertan por orden,
    * en el campo llamado columns[i] en la tabla dada se insertara el valor values[i]
    * @return bool Debuelve TRUE si la insercion se ha realizado con exito,
    * FALSE en caso contrario o DIE si la consulta falla realiza un die mostrando por pantalla el error mysql
   */
   public function insert($table, $columns, $values)
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "insert");
      //Comprueba que ambos arrays tienen el mismo numero de campos, para cada columna hay un valor
      if(count($columns) != count($values))
         return FALSE;
      //Filtra las comillas simples
      $values = $this->sql_filter($values);
      //Construye la consulta
      $sql = $this->build_sql_insert($table, $columns, $values);
      //Realiza la consulta
      $result = $this->myquery($sql);
      if (!$result) {
         die('Invalid query: ' . mysql_error());
      }
      return $this->last_id($this->db_link);
   }

   /**
    * Modifica mediante la conexion abierta los valores especificados por orden
    * en las columnas especificadas en la tabla dada en la posicion correspondiente
    * al id.
    *
    * @param string $table  nombre de la tabla en la que se va a realizar la modificacion
    * @param array $columns nombre de las columnas en las que se van a modificar valores
    * @param array $values  valores modificados en cada columna. Se modifican por orden, en el
                  campo llamado columns[i] en la tabla dada se modificara el valor values[i]
    * @param string $condition  en caso que el $id valga FALSE se utiliza este campo que es directamente
                        la condicion a cumplir para que se realize el borrado.
    * @return bool  debuelve TRUE si la modificacion se ha realizado con exito, FALSE en caso contrario
    *               o DIE si la consulta falla realiza un die mostrando por pantalla el error mysql
    */
    public function update($table, $columns, $values, $condition = FALSE)
    {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "update");
      //Comprueba que ambos arrays tienen el mismo numero de campos, para cada columna hay un valor
      if(count($columns) != count($values))
         return FALSE;
      //Filtra las comillas simples
      $values = $this->sql_filter($values);
      //Construye la consulta
      $sql = $this->build_sql_update($table, $columns, $values, $condition);
      //Realiza la consulta
      $result = $this->myquery($sql);
      if (!$result) {
         die('Invalid query: ' . mysql_error());
      }
      return TRUE;
    }

   /**
    * Borra mediante la conexion abierta los valores especificados que cumplan
    * la condicion dada.
    *
    * @param string $table  nombre de la tabla en la que se va a realizar el borrado
    * @param string $condition condicion que han de cumpir los registros para ser borrados
    * @return boolean
    * devuelve si la consulta se ha ejecutado con exito o DIE si no ha podido ejecutar la consulta
    *
    * @todo Si en la condicion hay alguna comilla fuera de lugar dará error y no se puede arreglar con:
    *    //Filtra las comillas simples
    *   $condition = $this->sql_filter($condition);
    */
    public function delete($table, $condition)
    {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "delete");
      //Construye la consulta
      $sql = $this->build_sql_delete($table, $condition);
      //Realiza la consulta
      $result = $this->myquery($sql);
      if (!$result) {
         die('Invalid query: ' . mysql_error());
      }
      return $result;
    }

    /**
     * Realiza un fetch asociativo sobre el recurso
     * @param resource $resource
     * @return array/false
     */
    public function fetch($resource){
        if($this->debug)  $this->outline(func_get_args(), get_class($this) , "fetch");

        return mysql_fetch_assoc($resource);
    }

   
   public function selected_rows($result)
   /*Devuelve el numero de filas en un resultado*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "selected_rows");
      return mysql_num_rows($result);
   }

   private function last_id($result){
       /*Devuelve el ultimo id modificado en una insercion*/
       return mysql_insert_id($result);
   }
   
   public function affected_rows()
   /*Devuelve el numero de filas afectadas por la ultima sentencia
   sobre el servidor asociado con el identificador del enlace de la clase (this->db_link).
   NOTA: Si la �ltima sentencia fue un DELETE sin clausula WHERE, todos los registros han sido borrados de la tabla pero esta funci�n devolvera cero.
   NOTA: Si est� usando transacciones, necesitar� llamar mysql_affected_rows() despu�s del INSERT, UPDATE, o DELETE, no despu�s del commit. 
   NOTA: Cuando se usa UPDATE, MySQL no actualizar� las columnas donde el nuevo valor es el mismo al actual. Esto crea la posibilidad de 
   que mysql_affected_rows() pueda no ser igual al n�mero de filas encontradas, solo el n�mero de filas que fueron literalmente afectadas por la sentencia.
   La sentencia REPLACE primero borra el registro con la misma llave principal y entonces inserta el nuevo registro. Esta funci�n regresa el n�mero 
   de registros borrados m�s el n�mero de registros insertados. 
   */
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "affected_rows");
      if(!$this->db_link)
         return FALSE;
      return mysql_affected_rows($this->db_link);
   }
   /* Private Functions */
   private function select_database()
   /*Selecciona la base de datos con la que trabaja la conexion abierta*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "select_database");
      if($this->database_name != NULL && $this->db_link != NULL)
         return mysql_select_db($this->database_name,$this->db_link);
      return FALSE;
   }
   
   private function build_sql_values($array, $separator = ",", $surround = "'")
   /*Bucle que compone las filas de una operacion sql a partir de un array de valores, 
   el separador (por defecto ,) y el simbolo que rodea a los valores (por defecto ')*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_values");
      $primera = TRUE;
      $sql = '';
      foreach($array as $a)
      {
         if($primera)
         {
            $sql = $sql . $surround . $a . $surround;
            $primera = FALSE;
         }
         else
            $sql = $sql . $separator . $surround . $a . $surround;
      }
      return $sql;
   }

   private function build_sql_equal($array, $separator = " , ", $surround = "'")
   /*Bucle que compone una fila de igualdades. Ej: id = 5, nombre = 'Jose', ...*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_values");
      $primera = TRUE;
      foreach($array as $index => $a)
      {
         if($primera)
         {
            $sql = $sql . $index . " = " . $surround . $a . $surround;
            $primera = FALSE;
         }
         else
            $sql = $sql . $separator . $index . " = " . $surround . $a . $surround;
      }
      return $sql;
   }
   
   private function build_sql_select($table, $fields, $condition, $limit, $order = FALSE)
   /*Construye la consulta sql que hace una selccion en la base de datos mysql*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_select");
      $sql = "SELECT ". $this->build_sql_values($fields, "," , "");
      $sql = $sql . " FROM ". $table;
      if($condition)
         $sql = $sql . " WHERE ". $condition;
      if($order)
         $sql = $sql . " ORDER BY " . $order;
      if($limit)
         $sql = $sql . " LIMIT ". $this->build_sql_values($limit, ",", "");
      return $sql;
   }
   
   private function build_sql_insert($table, $columns, $values)
   /*Construye la consulta sql que hace una insercion en la base de datos mysql*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_insert");
      $sql = "INSERT INTO ".$table." (";
      $sql = $sql . $this->build_sql_values($columns, ",", "");
      $sql = $sql . ") VALUES (";
      $sql = $sql . $this->build_sql_values($values);
      $sql = $sql . ")";
      return $sql;
   }

   private function build_sql_update($table, $columns, $values, $condition = FALSE)
   /*Construye la consulta sql que hace una modificacion en la base de datos mysql*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_update");

      if(count($columns) == count($values)) {
          $sql = "UPDATE ".$table." SET ";

          $sql = $sql . array_pop($columns) . " = '" . array_pop($values) . "'";

          $size = count($columns);
          for($i = 0; $i < $size; $i++)
                $sql = $sql . " , " . array_pop($columns) . " = '" . array_pop($values) . "'";

          if($condition)
             $sql = $sql ." WHERE " . $condition;
          return $sql;
      }
      return false;
   }
   
   private function build_sql_delete($table, $condition = FALSE)
   /*Construye la consulta sql que hace un borrado en la base de datos mysql*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "build_sql_delete");
      $sql = "DELETE FROM ". $table;
      if($condition)
         $sql = $sql ." WHERE " . $condition;
      return $sql;
   }

   /**
    * Funcion a llamar antes de hacer una operacion con la base de datos para filtrar las comillas.
    *
    * @param String/Array $string   Frase o array de frases de las que queremos filtrar las comillas
    * @return String/Array  Los datos entrantes con las comillas filtradas, susittuimos "'" por "\'"
    */
   private function sql_filter($string){
       if($this->debug)  $this->outline(func_get_args(), get_class($this) , "sql_filter");
       if(!$string)  return false;
       if(is_array($string)){
           foreach($string as $index => $dato){
            $result[$index] = str_replace("\'", "'", $dato);
            $result[$index] = str_replace("'", "\'", $result[$index]);
           }
           return $result;
       }
       return str_replace("'", "\'", $string);
   }
   
   private function sql_safe($string)
   /*Pasando por esta funcion cualquier consulta a la base de datos que venga hecha desde el usuario
   filtramos cualquier problema de sqlInyection*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "sql_safe");
      if(get_magic_quotes_gpc())
         {
         $string = stripslashes($string);
         }
      $badWords = "(delete)|(update)|(union)|(insert)|(drop)|(http)|(--)";
      $string = eregi_replace($badWords, "", $string);
      if (phpversion() >= '4.3.0')
         {
         $string = mysql_real_escape_string($string);
         }
      else
         {
         $string = mysql_escape_string($string);
         }
      return $string;
   }
   
   private function myquery($sql)
   /*Realiza las consultas*/
   {
      if($this->debug)  $this->outline(func_get_args(), get_class($this) , "myquery");
      return mysql_query($sql , $this->db_link);
   }
}//End class

?>
